/**
 * @param url 文件下载地址
 * @param filename 下载后保存的文件名（带扩展名）
 * @param onProgress 下载进度回调函数（单位：百分比）
 */
export interface DownloadFileOptions {
    url: string
    filename: string
    onProgress?: (downloaded: number, total: number) => void
    signal?: AbortSignal
    /**
     * 下载完成后的回调
     */
    onSuccess?: () => void
    /**
     * 下载失败或取消下载时的回调
     * @param error
     */
    onError?: (error: unknown) => void
}

/**
 * created by yangtong on 2025/5/30 下午11:05
 * <br />
 * 以流方式下载文件，支持进度回调
 * <br />
 * 所有数据将保存在内存中（Blob 对象），适用于小至中型文件，若文件过大，可能造成内存占用过高甚至崩溃
 * @param options 下载文件的参数
 */
export async function downloadFile({
                                       url,
                                       signal,
                                       onProgress,
                                       onError
                                   }: {
                                       url: string
                                       signal?: AbortSignal
                                       onProgress?: (received: number, total: number) => void
                                       onError?: (err: unknown) => void
                                   }
): Promise<Blob> {
    try {
        const res = await fetch(url, {signal})

        if (!res.ok) {
            throw new Error(`下载失败：${res.status} ${res.statusText}`)
        }

        const total = Number(res.headers.get('Content-Length')) || -1
        if (!res.body) {
            throw new Error('响应流为空，无法下载（res.body 为 null）')
        }

        if (total === -1 && onProgress) {
            console.warn('响应未包含 Content-Length，无法计算下载进度')
        }

        const reader = res.body.getReader()
        let received = 0

        const stream = new ReadableStream({
            start(controller) {
                function pump(): void {
                    reader.read().then(({done, value}) => {
                        if (done) {
                            controller.close()
                            if (onProgress && total > 0) {
                                onProgress(total, total)
                            }
                            return
                        }

                        if (value) {
                            received += value.length
                            if (onProgress && total > 0) {
                                onProgress(received, total)
                            }
                            controller.enqueue(value)
                        }

                        pump()
                    })
                }

                pump()
            }
        })

        //等待整个文件数据都下载完成、拼接完毕
        return await new Response(stream).blob()
    } catch (err) {
        // ✅ 出错时回调
        onError?.(err)
        throw err // 仍然抛出给调用者处理（可选）
    }
}

/**
 * 下载超大文件（让浏览器接管下载流程，避免内存占用）
 * 注意：该方式不支持进度条、不支持取消，只适合大文件！
 *
 * @param url 文件下载地址
 * @param filename 可选的保存文件名（如果不传，则浏览器按服务器响应或 URL 推断）
 * @param confirm 是否在下载前提示用户（可选）
 */
export function downloadLargeFile(
    {
        url,
        filename,
        confirm = false
    }: {
        url: string
        filename?: string
        confirm?: boolean
    }
): void {
    if (confirm) {
        const proceed = window.confirm('该文件较大，是否开始下载？')
        if (!proceed) return
    }

    const link = document.createElement('a')
    link.href = url

    // 浏览器仅在同源或允许 CORS + attachment 时，会识别 download 属性
    if (filename) {
        link.download = filename
    }

    // 模拟点击，触发浏览器默认下载行为（会边下载边写入磁盘）
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
}

